#include<iostream>
#include<unistd.h>
#include<vector>
#include<string>
#include<ctime>
#include<sys/types.h>
#include<sys/wait.h>

#define PROCESS_COUNT 10 //创建的子进程个数
#define TASK_COUNT 100  //任务的数量

using std::vector;
using std::string;
using std::cout;
using std::endl;

struct Info_pro//描述子进程的属性
{
    int _pid;//进程的pid---索引
    int _wfd;//向进程派发任务的管道接口
    string _pro_name;//进程的“名字”

    Info_pro(int pid,int wfd,const string& pro_name):_pid(pid),_wfd(wfd),_pro_name(pro_name) {}
};
//子进程任务的执行接口
void Handler()
{
    while(1){
        int ret;
        int n=read(0,&ret,sizeof(ret));//当没有数据时，子进程阻塞在这里
        if(n<0){
            perror("read fail...");
            return;
        }
        else if(n==0){
            cout<<"Dispatcher exit,me too..."<<endl;
            break;
        }
        else{
            cout<<getpid()<<",read a data:"<<ret<<endl;//对任务的简单处理
        }
        //sleep(1);
    }
}
//进程池初始化
void process_pool_init(vector<Info_pro>* v)
{
    vector<int> extra_fd;
    //父进程向管道写入数据，子进程从管道读取数据
    for(int i=0;i<PROCESS_COUNT;i++)
    {
        //sleep(1);
        int pipefd[2];//pipefd[0]是文件的读接口，pipefd[1]是文件的写接口
        int ret=pipe(pipefd);//结果就不判断了
        //创建子进程
        int id=fork();
        if(id==0){
            cout<<"clsoe extra fd in history:";
            for(auto old_fd:extra_fd){
                close(old_fd);//关闭子进程多余的fd
                cout<<old_fd<<" ";
            }
            cout<<endl;
            //子进程执行 "读" 功能
            close(pipefd[1]);
            dup2(pipefd[0],0);//输出重定向，让子进程调用read()时，直接从0读取数据

            Handler();//处理任务
            exit(0);
        }
        //父进程执行 "写" 功能
        close(pipefd[0]);
        string name="process_"+std::to_string(i);
        v->push_back({id,pipefd[1],name});//将子进程的信息纳入主进程的管理容器中
        extra_fd.push_back(pipefd[1]);//创建下一个子进程时，新创建出来的子进程的文件描述符表含有对本次文件的写端口fd，我们要在子进程内部将其关闭
    }
}
//调试接口
void Debug(const vector<Info_pro>& v)
{
    for(const auto& inf:v)
    {
        cout<<inf._pro_name<<",pid:"<<inf._pid<<",wfd:"<<inf._wfd<<endl;
    }
}
//主进程进行任务派发
void Dispatch_task(const vector<Info_pro>& v)
{
    srand(time(0));
    //随机派发给各个进程
    for(int i=0;i<TASK_COUNT;i++)
    {
        //生成一个随机数
        int pos=rand()%v.size();
        //派发任务
        cout<<"dispatch a task "<<i<<" to"<<v[pos]._pro_name<<endl;
        write(v[pos]._wfd,&i,sizeof(i));
        
        //sleep(1);
    }
}
//进程等待，资源回收，并获取进程的退出信息
void Wait(const vector<Info_pro>& v)
{
    for(const auto& inf:v)
    {
        close(inf._wfd);//管道的写端关闭离开，子进程read会读到0
    }

    for(const auto& inf:v)
    {
        int status;
        waitpid(inf._pid,&status,0);//子进程exit后，回收子进程的资源，并获取子进程的退出信息
        cout<<inf._pro_name<<"exit,exception code is:"<<(status&0x7F)<<"exit code:"<<((status>>8)&0xFF)<<endl;
    }
}

int main()
{
    vector<Info_pro> v;//管理所有进程的数据结构
    
    //1.初始化进程池
    process_pool_init(&v);

    //测试
    //Debug(v);

    //2.派发任务
    Dispatch_task(v);

    //3.资源清理——进程等待
    Wait(v);

    return 0;
}